﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace CoreLibrary.Security {

    public sealed class Cryptos {

        /**
         * Aes Crypto Alogrithm
         * ***/
        public static Cryptos CreateAes(byte[] key, byte[] value) {
            return new Cryptos(Aes.Create(), key, value);
        }

        /**
         * Rajindael Crypto Alogrithm
         * ***/
        public static Cryptos CreateRajindael(byte[] key, byte[] value) {
            return new Cryptos(Rijndael.Create(), key, value);
        }

        private readonly byte[] _cipherKey;
        private readonly byte[] _cipherValue;
        private readonly SymmetricAlgorithm _algorithm;
        
        public Cryptos(SymmetricAlgorithm alg, 
                               byte[] key, 
                               byte[] iv) {
            _algorithm   = alg;
            _cipherKey   = key;
            _cipherValue = iv;
        }

        public Cryptos(SymmetricAlgorithm alg, 
                      string base64Key, 
                      string base64Iv) 
            : this(alg, 
                   Convert.FromBase64String(base64Key), 
                   Convert.FromBase64String(base64Iv)) {
        }

        /***
         * Bianry Array Encryption
         * ****/
        public byte[] Encrypt(byte[] data) {
            return Crypt(data, _algorithm.CreateEncryptor(_cipherKey, _cipherValue));
        }

        public byte[] Decrypt(byte[] encrpted) {
            return Crypt(encrpted, _algorithm.CreateDecryptor(_cipherKey, _cipherValue));
        }

        /***
         * Base64 Encryption
         * ***/
        public string EncryptToBase64(string data) {
            var cryptedData = Crypt(Encoding.UTF8.GetBytes(data),
                                    _algorithm.CreateEncryptor(_cipherKey, _cipherValue)
            );
            return Convert.ToBase64String(cryptedData);
        }

        public string DecryptFromBase64(string base64String) {
            var cryptedData = Crypt(Convert.FromBase64String(base64String),
                                    _algorithm.CreateDecryptor(_cipherKey, _cipherValue)
            );
            return Encoding.UTF8.GetString(cryptedData);
        }

        /***
         * Base Crypto Method
         * ***/
        private static byte[] Crypt(byte[] value, ICryptoTransform transform) {
            var m = new MemoryStream(value.Length * 2);
            using (var cryptoStream = new CryptoStream(m, transform, CryptoStreamMode.Write)) {
                   cryptoStream.Write(value, 0, value.Length);
            }
            return m.ToArray();
        }
        
    }
}